package com.hmall.common.utils;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@RequiredArgsConstructor
public class RabbitMqHelper {
    
    private final RabbitTemplate rabbitTemplate;
    
    /**
     * 发送消息到指定交换机和路由键
     * @param exchange 交换机名称
     * @param routingKey 路由键
     * @param message 消息内容
     */
    public void send(String exchange, String routingKey, Object message) {
        try {
            rabbitTemplate.convertAndSend(exchange, routingKey, message);
            log.info("发送消息成功，exchange={}, routingKey={}, message={}", exchange, routingKey, message);
        } catch (Exception e) {
            log.error("发送消息失败，exchange={}, routingKey={}, message={}", exchange, routingKey, message, e);
            throw new RuntimeException("消息发送失败", e);
        }
    }
    
    /**
     * 发送消息到指定队列
     * @param queue 队列名称
     * @param message 消息内容
     */
    public void sendToQueue(String queue, Object message) {
        try {
            rabbitTemplate.convertAndSend(queue, message);
            log.info("发送消息到队列成功，queue={}, message={}", queue, message);
        } catch (Exception e) {
            log.error("发送消息到队列失败，queue={}, message={}", queue, message, e);
            throw new RuntimeException("消息发送失败", e);
        }
    }
    
    /**
     * 发送延迟消息
     * @param exchange 交换机名称
     * @param routingKey 路由键
     * @param message 消息内容
     * @param delay 延迟时间(毫秒)
     */
    public void sendDelayMessage(String exchange, String routingKey, Object message, long delay) {
        try {
            rabbitTemplate.convertAndSend(exchange, routingKey, message, msg -> {
                msg.getMessageProperties().setDelay(Math.toIntExact(delay));
                return msg;
            });
            log.info("发送延迟消息成功，exchange={}, routingKey={}, delay={}ms, message={}", 
                    exchange, routingKey, delay, message);
        } catch (Exception e) {
            log.error("发送延迟消息失败，exchange={}, routingKey={}, delay={}ms, message={}", 
                    exchange, routingKey, delay, message, e);
            throw new RuntimeException("延迟消息发送失败", e);
        }
    }

    /**
     * 发送消息并等待确认，支持重试机制
     * @param exchange 交换机名称
     * @param routingKey 路由键
     * @param msg 消息内容
     * @param maxRetries 最大重试次数
     */
    public void sendMessageWithConfirm(String exchange, String routingKey, Object msg, int maxRetries) {
        int attempts = 0;
        while (attempts < maxRetries) {
            try {
                // 发送消息并等待确认
                rabbitTemplate.convertAndSend(exchange, routingKey, msg);
                log.info("发送消息成功，exchange={}, routingKey={}, message={}", exchange, routingKey, msg);
                return; // 成功发送则返回
            } catch (Exception e) {
                attempts++;
                log.error("发送消息失败，attempt={}, exchange={}, routingKey={}, message={}",
                        attempts, exchange, routingKey, msg, e);
                if (attempts >= maxRetries) {
                    log.error("达到最大重试次数，消息发送最终失败，exchange={}, routingKey={}, message={}",
                            exchange, routingKey, msg);
                    throw new RuntimeException("消息发送失败，已重试" + maxRetries + "次", e);
                }
                // 等待一段时间后重试
                try {
                    Thread.sleep(1000 * attempts); // 指数退避策略
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new RuntimeException("线程中断", ie);
                }
            }
        }
    }

}